package com.wontube.client.remote;

import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * @author yuechao
 *
 */
public final class Remoting<T> {
	public static final String dataFormatJava = "java";
	public static final String dataFormatJson = "json";
	public static final String dataFormatPHP = "php";
	public static final String dataFormatHessian = "hessian";

	private T remoteClass;
	private ProxyClient client = new ProxyClient();
	
	private static final ArrayList<IRemotingCreateListener> createListeners = new ArrayList<IRemotingCreateListener>();
	
	public Remoting() {
		for (IRemotingCreateListener listener : createListeners) {
			listener.onCreate(this);
		}
	}
	
	public static void addCreateListener(IRemotingCreateListener listener) {
		createListeners.add(listener);
	}
	
	public static boolean removeCreateListener(IRemotingCreateListener listener) {
		return createListeners.remove(listener);
	}
	
	public Remoting<T> setServerUrl(String value) {
		this.client.setServerUrl(value);
		return this;
	}
	
	public String getServerUrl() {
		return this.client.getServerUrl();
	}
	
	public String getRemoteUrl() {
		return this.client.getRemoteUrl();
	}
	
	public String getClientSessionId() {
		return this.client.getClientSessionId();
	}
	
	public Remoting<T> setClientSessionId(String value) {
		this.client.setClientSessionId(value);
		return this;
	}
	
	public boolean isDone() {
		return this.client.isDone();
	}
	
	public Remoting<T> setDone(boolean value) {
		this.client.setDone(value);
		return this;
	}
	
	public int getConnectTimeout() {
		return this.client.getConnectTimeout();
	}
	
	public Remoting<T> setConnectTimeout(int timeout) {
		this.client.setConnectTimeout(timeout);
		return this;
	}
	
	public int getReadTimeout() {
		return this.client.getReadTimeout();
	}
	
	public Remoting<T> setReadTimeout(int timeout) {
		this.client.setReadTimeout(timeout);
		return this;
	}
	
	public T getRemoteClass() {
		return this.remoteClass;
	}
	
	public Remoting<T> setRemoteClass(T value) {
		this.remoteClass = value;
		return this;
	}
	
	public String getLastErrMsg() {
		return this.client.getErrorMsg();
	}
	
	public Remoting<T> setLastErrMsg(String value) {
		this.client.setErrorMsg(value);
		return this;
	}
	
	public String getApiVersion() {
		return this.client.getApiVersion();
	}
	
	public Remoting<T> setApiVersion(String value) {
		this.client.setApiVersion(value);
		return this;
	}
	
	public String getDataFormat() {
		return this.client.getDataFormat();
	}
	
	public HashMap<String, String> getRequestExtHeaders() {
		return this.client.getRequestExtHeaders();
	}

	public void setRequestExtHeaders(HashMap<String, String> requestExtHeaders) {
		this.client.setRequestExtHeaders(requestExtHeaders);
	}
	
	public Remoting<T> setDataFormat(String value) {
		this.client.setDataFormat(value);
		return this;
	}
	
	public HashMap<String, String> getHeaders() {
		return this.client.getHeaders();
	}

	@SuppressWarnings("unchecked")
	public final T createService(Class<T> type) {
    	DefaultInvocationHandler handler = new DefaultInvocationHandler(this.client);
        if (type.isInterface()) {
            this.remoteClass = (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[] { type }, handler);
        } else {
            this.remoteClass = (T) Proxy.newProxyInstance(type.getClassLoader(), type.getInterfaces(), handler);
        }
    	return this.remoteClass;
    }

	@SuppressWarnings("unchecked")
	public final T createService(Class<T>[] interfaces) {
    	DefaultInvocationHandler handler = new DefaultInvocationHandler(this.client);
    	this.remoteClass = (T) Proxy.newProxyInstance(interfaces[0].getClassLoader(), interfaces, handler);
    	
    	return this.remoteClass;
    }
	
	/**
	 * @deprecated please use createService instead
	 * 
	 * @param type
	 * @return
	 */
    @SuppressWarnings("unchecked")
    @Deprecated
	public final Remoting<T> useService(Class<T> type) {
    	DefaultInvocationHandler handler = new DefaultInvocationHandler(this.client);
        if (type.isInterface()) {
            this.remoteClass = (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[] { type }, handler);
        } else {
            this.remoteClass = (T) Proxy.newProxyInstance(type.getClassLoader(), type.getInterfaces(), handler);
        }
        return this;
    }

    /**
     * @deprecated please use createService instead
     * 
     * @param interfaces
     * @return
     */
    @SuppressWarnings("unchecked")
    @Deprecated
	public final Remoting<T> useService(Class<T>[] interfaces) {
    	DefaultInvocationHandler handler = new DefaultInvocationHandler(this.client);
    	this.remoteClass = (T) Proxy.newProxyInstance(interfaces[0].getClassLoader(), interfaces, handler);
    	
    	return this;
    }
}
